<template>
	<div class="lexmis-Tippy">
		<slot></slot>
		<div
			v-if="isOutContent"
			ref="content"
			:style="style">
			<div
				v-if="head"
				class="lexmis_head">
				<div
					class="lexmis_title"
					:style="titleStyle">
					<slot name="title">{{title}}</slot>
				</div>
				<div
					v-if="closable"
					class="lexmis_close">
					<Icon name="close" @click="hide"/>
				</div>
			</div>
			<BothScrollArea
				v-if="showContent"
				ref="scroll"
				:v-visible="vVisible"
				:h-visible="hVisible"
				:style="bodyStyle"
				class="lexmis_body"
				@resize="$_lexmis_resize"
				@inner-resize="$_lexmis_innerResize">
				<slot
					name="content"
					:width="outerWidth"
					:height="outerHeight">
					<div
						class="lexmis_tippyContent"
						:style="contentStyle">{{content}}</div>
				</slot>
			</BothScrollArea>
		</div>
	</div>
</template>

<script>
import 'tippy.js/dist/tippy.css';
import 'tippy.js/animations/scale.css';
import tippy from 'tippy.js';
import Icon from '../icon';
import BothScrollArea from '../both-scroll-area';
import {convertCssLength} from '../../../util/common';

/**
 * @author 唐国雄
 * 提示
 * 属性----------------------
 * v-model			是否显示
 * :title			提示标题
 * :content			提示内容
 * :advanced		高级模式(和closable只要有一个为true就可以使用插槽)
 * :head			是否有标题
 * :closable		是否有关闭按钮(和advanced只要有一个为true就可以使用插槽)
 * :min-width		提示框最小宽度
 * :max-width		提示框最大宽度
 * :max-height		提示框最大高度
 * :width			提示框宽度,支持带单位和不带单位,closable或advanced为true才有效
 * :height			提示框高度,支持带单位和不带单位,closable或advanced为true才有效,不设置表示根据内容高度
 * :append-to		提示元素绑定在哪里,默认document.body
 * :disable			是否禁用
 * :tippy-options	传递给tippy的选项,被合并
 * :v-visible		纵向滚动条显示状态
 * :h-visible		横向滚动条显示状态
 * 事件----------------------
 * @show			开始显示
 * @shown			显示动画完毕
 * @hide			开始隐藏
 * @hidden			隐藏动画完毕
 * @resize			body大小改变事件,{width:number,height:number}
 * @inner-resize	提示内容大小改变事件,{width:number,height:number}
 * 方法----------------------
 * show()		显示提示
 * hide()		隐藏提示
 * 插槽----------------------
 * #default		提示附着的元素
 * #title		提示标题(比属性优先级高)
 * #content		提示内容(比属性优先级高), {width:number,height:number}
 * 引用----------------------
 * content		复杂提示框
 * scroll		body部分的ScrollArea组件
 */
export default {
	name:'Tippy',
	components:{
		Icon,
		BothScrollArea,
	},
	props:{
		//是否显示
		value:Boolean,
		//标题
		title:String,
		//内容
		content:String,
		//高级模式(可以使用插槽)
		advanced:Boolean,
		//是否有标题,closable或advanced为true才有效
		head:{
			type:Boolean,
			default:true
		},
		//可关闭
		closable:Boolean,
		//提示框最小宽度
		minWidth:Number,
		//提示框最大宽度
		maxWidth:Number,
		//提示框最大高度
		maxHeight:Number,
		//提示框宽度,closable或advanced为true才有效
		width:{
			type:[Number,String],
			default:300
		},
		//提示框高度,closable或advanced为true才有效,不设置表示根据内容高度
		height:{
			type:[Number,String],
			default:null
		},
		//提示元素绑定在哪里,默认document.body
		appendTo:null,
		//是否禁用
		disable:Boolean,
		//传递给tippy的选项,被合并
		tippyOptions:{
			type:Object,
			default(){
				return {};
			}
		},
		//纵向滚动条显示状态
		vVisible:{
			type:Boolean,
			default:null,
		},
		//横向滚动条显示状态
		hVisible:{
			type:Boolean,
			default:null,
		},
	},
	data(){
		return {
			//容器宽度
			outerWidth:0,
			//容器高度
			outerHeight:0,
			//实际内容高度
			contentHeight:0,
			//实际内容宽度
			contentWidth:0,
			//容器宽高的限制
			limitStyle:{},
			//显示内容(用v-if控制内容的生命周期)
			showContent:false,
			//tippy被初始化
			inital:false,
		};
	},
	computed:{
		style(){
			return Object.assign({
				width:this.inital?(this.width?convertCssLength(this.width):this.contentWidth+'px'):0,
				height:this.height?convertCssLength(this.height):null,
			},this.limitStyle);
		},
		titleStyle(){
			return {
				paddingRight:this.closable?null:'20px',
			};
		},
		bodyStyle(){
			return {
				height:this.height?null:this.contentHeight+'px',
			};
		},
		contentStyle(){
			return {
				paddingTop:this.head?null:'10px',
			};
		},
		isOutContent(){
			return this.advanced||this.closable;
		},
		options(){
			const tippyOptions=this.tippyOptions;
			const options={
				animation:'scale',
				...tippyOptions,
				appendTo:this.appendTo??document.body,
				onHide:(instance) => {
					this.$emit('hide',instance);
					this.$emit('input',false);
					if(tippyOptions.onHide){
						tippyOptions.onHide(instance);
					}
				},
				onHidden:(instance) => {
					this.$emit('hidden',instance);
					if(tippyOptions.onHidden){
						tippyOptions.onHidden(instance);
					}
				},
				onShow:(instance) => {
					this.$emit('show',instance);
					this.$emit('input',true);
					if(tippyOptions.onShow){
						tippyOptions.onShow(instance);
					}
				},
				onShown:(instance) => {
					this.$emit('shown',instance);
					if(tippyOptions.onShown){
						tippyOptions.onShown(instance);
					}
				},
			};
			if(this.maxWidth){
				options.maxWidth=this.maxWidth;
			}
			if(this.isOutContent){
				return {
					maxWidth:'none',
					trigger:'click',
					hideOnClick:true,
					theme:'advanced-tip',
					...options,
					onShow:(instance) => {
						options.onShow(instance);
						this.showContent=true;
					},
					onMount:({popperInstance:{state:{placement}},reference}) => {
						const {left,top,width,height}=reference.getBoundingClientRect();
						if(placement.startsWith('top')||placement.startsWith('bottom')){
							this.limitStyle={
								maxHeight:Math.floor(Math.max(top,innerHeight-height-top)-40)+'px',
							};
						}else{
							this.limitStyle={
								maxWidth:Math.floor(Math.max(left,innerWidth-width-left)-40)+'px',
							};
						}
						if(this.minWidth){
							this.$set(this.limitStyle,'minWidth',this.minWidth+'px');
						}
						if(this.maxWidth){
							this.$set(this.limitStyle,'maxWidth','100%');
						}
						if(this.maxHeight){
							this.$set(this.limitStyle,'maxHeight',this.maxHeight+'px');
						}
						this.$set(this.limitStyle,'opacity',0);
						this.tipInstance.popperInstance.update().then(({rects:{popper:{width,height}}}) => {
							if(this.height||this.contentHeight){
								//固定高度,或者动态高度且有高度了才进入这
								this.$set(this.limitStyle,'height',height+'px');
								this.$set(this.limitStyle,'opacity',1);
							}
						});
					},
					onHidden:(instance) => {
						options.onHidden(instance);
						this.contentHeight=0;
						this.showContent=false;
					},
					content:this.$refs.content,
					interactive:true,
				};
			}else{
				return {
					hideOnClick:false,
					...options,
					content:this.content,
				};
			}
		},
	},
	mounted:function(){
		this.$nextTick(function(){
			this.tipInstance=tippy(this.$el,this.options);
			this.inital=true;
			this.$watch('options',function(val){
				this.tipInstance.setProps(val);
			});
			this.$watch('value',function(val){
				if(val!=null){
					if(val){
						this.show();
					}else{
						this.hide();
					}
				}
			},{
				immediate:true,
			});
			this.$watch('disable',function(val){
				if(val){
					this.tipInstance.disable();
				}else{
					this.tipInstance.enable();
				}
			},{
				immediate:true,
			});
			this.$watch('contentHeight',function(val){
				if(val&&!this.height){
					//因为是动态高度才会进入这
					this.$set(this.limitStyle,'height','');
					this.$set(this.limitStyle,'opacity',0);
					this.tipInstance.popperInstance.update().then(({rects:{popper:{width,height}}}) => {
						this.$set(this.limitStyle,'height',height+'px');
						this.$set(this.limitStyle,'opacity',1);
					});
				}
			});
		});
	},
	beforeDestroy:function(){
		this.$nextTick(function(){
			this.tipInstance.destroy();
		});
	},
	methods:{
		//容器大小变化
		$_lexmis_resize(size){
			this.$emit('resize',size);
			this.outerWidth=size.width;
			this.outerHeight=size.height;
		},
		//实际内容大小变化
		$_lexmis_innerResize(size){
			this.$emit('inner-resize',size);
			this.contentHeight=size.height;
			this.contentWidth=size.width;
		},
		show(){
			this.tipInstance.show();
		},
		hide(){
			this.tipInstance.hide();
		},
	}
};
</script>

<style lang="scss">
.lexmis-Tippy{
	display:inline-block;
	vertical-align:bottom;
}
//修复tippy的ie中bug
.tippy-box[data-placement^=top]>.tippy-arrow:before{
	border-top-color:inherit !important;
}
.tippy-box[data-placement^=bottom]>.tippy-arrow:before{
	border-bottom-color:inherit !important;
}
.tippy-box[data-placement^=left]>.tippy-arrow:before{
	border-left-color:inherit !important;
}
.tippy-box[data-placement^=right]>.tippy-arrow:before{
	border-right-color:inherit !important;
}
// 提示折行
[data-tippy-root]{
	>.tippy-box>.tippy-content{
		word-break:break-all;
	}
}
.tippy-box[data-theme~='advanced-tip']{
	background-color:#fff;
	color:#000;
	>.tippy-arrow{
		color:#fff;
		z-index:1;
	}
	>.tippy-content{
		border-radius:4px;
		box-shadow:0 0 10px 0 rgba(12, 12, 12, 0.2);
		padding:0;
		>div{
			$head-height:35px;
			max-width:calc(100vw - 40px);
			max-height:calc(100vh - 40px);
			display:flex;
			flex-direction:column;
			>.lexmis_head{
				flex-shrink:0;
				display:flex;
				height:$head-height;
				margin-top:5px;
				>.lexmis_title{
					width:100%;
					height:100%;
					line-height:$head-height;
					padding-left:20px;
					font-size:16px;
					white-space:nowrap;
					overflow:hidden;
					text-overflow:ellipsis;

				}
				>.lexmis_close{
					flex-shrink:0;
					width:$head-height;
					height:100%;
					display:flex;
					justify-content:center;
					align-items:center;
					>.lexmis-Icon{
						color:#999;
						font-size:18px;
						cursor:pointer;
						&:hover{
							color:#444;
						}
					}
				}
			}
			>.lexmis_body{
				flex-grow:1;
				color:#555;
				overflow:hidden;
				.lexmis_tippyContent{
					padding:0 20px 10px;
				}
			}
		}
	}
}
</style>
